package src.ee.ioc.smaug.parser;

import src.ee.ioc.smaug.fsm.*;
import java.io.File;
import src.ee.ioc.smaug.world.evolution.EnvDescription;

/**
 * Writes fsm to xml file
 * 
 * @author Margarita Spichakova
 * 
 */
public class FSMXMLWriter {
    /**
     * Entiy of XML writer
     */
    static XMLWriter write = new XMLWriter(EnvDescription.FSMXMLfilename);

    /**
     * Writes down whole machine to xml
     * 
     * @param fsm
     *            state machine to write
     * @param description
     *            of the machine
     */
    public static void writeFSM(FiniteStateMachine fsm, String description) {

        write.writePreface("1.0", "UTF-8", new File(EnvDescription.fsmdtd).toURI().toString());
        write.writeStylesheet(new File(EnvDescription.fsmxsl).toURI().toString());

        write.openEntryTag("fsm");
        write.writeAttribute("mtype", getType());
        write.writeAttribute("numberofstates", Integer.toString(fsm
                .getNumOfStates()));
        write.writeAttribute("description", description);
        write.closeEntryTag();

        writeAlphabet(fsm.getInputAlphabet(), "input");
        writeAlphabet(fsm.getOutputAlphabet(), "output");

        writeStates(fsm);
        writeTransitions(fsm);
        write.closeEntry("fsm");

        write.closeWriter();

    }

    /**
     * Writes down the alphabet
     * 
     * @param alpha
     *            the alphabet itself
     * @param type
     *            the type of the alphabet
     */
    private static void writeAlphabet(Alphabet alpha, String type) {
        write.openEntryTag("alphabet");
        write.writeAttribute("atype", type);
        write.closeEntryTag();

        for (int i = 0; i < alpha.getSizeOfAlphabet(); i++) {
            write.openEntryTag("char");
            write.writeAttribute("ctype", type);
            write
                    .writeAttribute("cvalue", alpha.returnSymbolAtPosition(i)
                            + "");
            write.closeEntryTag();
            write.closeEntry("char");
        }
        write.closeEntry("alphabet");

    }

    /**
     * Writes down all states
     * 
     * @param fsm
     *            state machine which states we want to write
     */
    private static void writeStates(FiniteStateMachine fsm) {
        write.openEntryTag("states");
        write.closeEntryTag();

        for (int i = 0; i < fsm.getNumOfStates(); i++) {
            State st = fsm.getStateAtPosition(i);
            if (st.isReachable()) {
                write.openEntryTag("state");

                write.writeAttribute("initial", st.isInitialState() + "");
                write.writeAttribute("final", st.isFinalState() + "");
                write.writeAttribute("svalue", st.getStateValue() + "");
                write.writeAttribute("id", st.getStateID() + "");

                write.closeEntryTag();
                write.closeEntry("state");
            }
        }
        write.closeEntry("states");

    }

    /**
     * Writes down the transitions
     * 
     * @param fsm
     *            state machine which states we want to write
     */
    private static void writeTransitions(FiniteStateMachine fsm) {
        write.openEntryTag("transitions");
        write.closeEntryTag();

        for (int i = 0; i < fsm.getNumOfTransitions(); i++) {
            Transition tr = fsm.getTransition(i);
            write.openEntryTag("transition");
            write.writeAttribute("from", tr.getFromState().getStateID() + "");
            write.writeAttribute("to", tr.getToState().getStateID() + "");
            write.writeAttribute("reading", tr.getInputSymbol() + "");
            write.writeAttribute("writing", tr.getOutputSymbol() + "");
            write.closeEntryTag();
            write.closeEntry("transition");

        }
        write.closeEntry("transitions");

    }

    /**
     * Type of the machine
     * 
     * @return type of the machine
     */
    private static String getType() {
        switch (EnvDescription.beingType) {
        case MOORE_MACHINE_FIXED:
            return "moore";
        case MOORE_MACHINE_MAX:
            return "moore";
        case MEALY_MACHINE_FIXED:
            return "mealy";
        default:
            return "moore";
        }

    }

}
